﻿using System;
using System.Collections.Generic;
using System.Linq;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Geometry;
using PlanningGIS.ArcGIS;
using PlanningGIS.Framework.Config;
using PlanningGIS.ManageUtility;
using PlanningGIS.Util.Log;
using System.IO;
using System.Runtime.InteropServices;
using System.Drawing;

namespace PlanningGIS.Framework
{
    /// <summary>
    /// 行政区划处理类
    /// </summary>
    public class RegionHelper
    {
        /// <summary>
        /// 行政区划名称前缀
        /// </summary>
        private const string REGION = "LEV";

        /// <summary>
        /// 行政代码字段名称
        /// </summary>
        public const string F_CODE = "Code";

        /// <summary>
        /// 行政名称字段名称
        /// </summary>
        public const string F_NAME = "Name";

        /// <summary>
        /// 区域位置（行政区、街道、社区等）数据集合对象
        /// </summary>
        private static Dictionary<string, IFeatureClass> _RegionList = null;

        /// <summary>
        /// 获取区域位置（行政区、街道、社区等）数据集合对象
        /// </summary>
        public static Dictionary<string, IFeatureClass> RegionList
        {
            get
            {
                if (_RegionList == null || _RegionList.Count == 0) GetLayerList();
                return _RegionList;
            }
        }

        /// <summary>
        /// 行政区图层根节点
        /// </summary>
        private static RegionNode _RegionRoot = null;

        /// <summary>
        /// 获取行政区图层根节点
        /// </summary>
        public static RegionNode RegionRoot
        {
            get
            {
                if (_RegionRoot == null) GetRegionNodes();
                return _RegionRoot;
            }
        }

        /// <summary>
        /// 行政区图标
        /// </summary>
        public static Dictionary<int,Bitmap> RegionImages { get; private set; }

        /// <summary>
        /// 最低级别的行政区要素类
        /// </summary>
        public static IFeatureClass LastFeatureClass { get; private set; }

        /// <summary>
        /// 用户自定义范围
        /// </summary>
        public static IGeometry UserRegion { get; private set; }
        
        /// <summary>
        /// 获取SysData中所有的结合表图层及比例尺
        /// </summary>
        private static void GetLayerList()
        {
            if (!Directory.Exists(AppConfig.DataFullName)) return;
            try
            {
                IWorkspace dataWorkspace = PlanningGIS.ArcGIS.WorkspaceHelper.OpenGDBWorkspace(AppConfig.DataFullName);
                List<IFeatureClass> featcls = GeodatabaseHelper.GetAllFeatureClass(dataWorkspace as IDataset, REGION);
                if (featcls == null || featcls.Count == 0) return;
                Dictionary<string, IFeatureClass> lst = new Dictionary<string, IFeatureClass>();
                foreach (IFeatureClass f in featcls)
                {
                    string name = ((IDataset)f).Name.Trim();
                    if (name.Contains(".")) name = name.Substring(name.IndexOf(".") + 1);
                    if (name.Length > 4) continue;
                    lst.Add(name, f);
                }
                _RegionList = lst.OrderBy(r => r.Key).ToDictionary(r => r.Key, r => r.Value);
            }
            catch (Exception ex)
            {
                LogHelper.WriteErrorText(ex);
            }
            
        }

        #region 区域

        /// <summary>
        /// 根据序号获取区域的数据集对象
        /// </summary>
        /// <param name="index">区域序号，从1开始</param>
        /// <returns></returns>
        public static IFeatureClass GetRegionFeatureClass(int index)
        {
            if (RegionList == null || RegionList.Count == 0) return null;
            if (RegionList.Count < index) return null;
            if (index < 1) return null;
            string clsname = REGION + index.ToString();
            return RegionList[clsname];
        }

        /// <summary>
        /// 根据区域编码获取区域的范围
        /// </summary>
        /// <param name="code">区域编码</param>
        /// <param name="outName">区域名称</param>
        /// <returns></returns>
        public static IPolygon GetRegionGeometryByCode(string code, ref string outName)
        {
            if (RegionList == null || RegionList.Count == 0) return null;
            IPolygon poly = null;
            foreach (KeyValuePair<string, IFeatureClass> kvp in RegionList)
            {
                poly = GetRegionGeometryByCode(kvp.Value, code, ref outName);
                if (poly == null) continue;
                break;
            }
            return poly;
        }

        /// <summary>
        /// 根据区域编码，从指定的区域数据集中获取区域的范围
        /// </summary>
        /// <param name="featureClass">区域数据集</param>
        /// <param name="code">区域编码</param>
        /// <param name="outName">区域名称</param>
        /// <returns></returns>
        public static IPolygon GetRegionGeometryByCode(IFeatureClass featureClass, string code, ref string outName)
        {
            IQueryFilter queryFilter = new QueryFilter();
            queryFilter.SubFields = "*";
            queryFilter.WhereClause = "Code='" + code + "'";
            IFeatureCursor pFeatureCursor = featureClass.Search(queryFilter, false);
            IFeature feature = pFeatureCursor.NextFeature();
            if (feature != null)
            {
                outName = feature.get_Value(feature.Fields.FindField("NAME")).ToString();
                return feature.ShapeCopy as IPolygon;
            }
            return null;
        }
        
        /// <summary>
        /// 根据区域编码获取区域的范围
        /// </summary>
        /// <param name="oid">记录唯一编号</param>
        /// <param name="featureclassname">要素类名称</param>
        /// <returns></returns>
        public static IPolygon GetRegionGeometry(int oid, string featureclassname)
        {
            if (RegionList == null || RegionList.Count == 0) return null;
            if (!RegionList.ContainsKey(featureclassname)) return null;
            IFeature feat = RegionList[featureclassname].GetFeature(oid);
            if (feat == null || feat.Shape == null || feat.Shape.IsEmpty) return null;
            return feat.Shape as IPolygon;            
        }
        
        #endregion

        /// <summary>
        /// 迭代查询时临时过渡的行政区节点
        /// </summary>
        private static RegionNode _TempRegionNode = null;

        /// <summary>
        /// 获取所有的行政区数据
        /// </summary>
        private static void GetRegionNodes()
        {
            if (RegionHelper.RegionList == null || RegionHelper.RegionList.Count == 0) return;
            RegionImages = new Dictionary<int, Bitmap>();
            int len = 0;
            foreach (KeyValuePair<string, IFeatureClass> kvp in RegionHelper.RegionList)
            {
                LastFeatureClass = kvp.Value;
                IFeature feat = null;
                int nextlen = 0;
                int idxNM = kvp.Value.Fields.FindField(RegionHelper.F_NAME);
                int idxCD = kvp.Value.Fields.FindField(RegionHelper.F_CODE);
                if (idxNM < 0 || idxCD < 0) continue;
                try
                {
                    IFeatureCursor cur = kvp.Value.Search(null, false);
                    while ((feat = cur.NextFeature()) != null)
                    {
                        RegionNode nd = new RegionNode()
                        {
                            OID = feat.OID,
                            Name = feat.get_Value(idxNM).ToString().Trim(),
                            Code = feat.get_Value(idxCD).ToString().Trim(),
                            LayerName = kvp.Key
                        };
                        nextlen = nd.Code.Length;
                        if (!RegionImages.ContainsKey(nextlen))
                        {
                            string fname = AppConfig.ImagePath + @"\icons\Region" + nextlen.ToString() + ".png";
                            try
                            {
                                if (File.Exists(fname))
                                {
                                    RegionImages.Add(nextlen, new Bitmap(fname));
                                }
                            }
                            catch
                            {
                                LogHelper.WriteErrLog("图片文件" + fname + "已损坏！");
                            }
                        }
                        nd.Nodes = new List<RegionNode>();
                        if (len == 0)
                        {
                            _RegionRoot = nd;
                            continue;
                        }
                        string subs = nd.Code.Substring(0, len);
                        if (!_RegionRoot.Code.Equals(subs, StringComparison.CurrentCultureIgnoreCase))
                        {
                            _TempRegionNode = null;
                            ExistsNode(subs, _RegionRoot.Nodes);
                            if (_TempRegionNode != null)
                            {
                                _TempRegionNode.Nodes.Add(nd);
                                continue;
                            }
                        }
                        _RegionRoot.Nodes.Add(nd);
                    }
                    len = nextlen;
                    if (feat != null) Marshal.ReleaseComObject(feat);
                    if (cur != null) Marshal.ReleaseComObject(cur);
                    feat = null;
                    cur = null;
                }
                catch (System.Exception ex)
                {
                    LogHelper.WriteErrLog("读取系统数据中的行政区信息失败：" + ex.Message);
                }
            }
        }

        /// <summary>
        /// 根据编码获取行政区节点
        /// </summary>
        /// <param name="code"></param>
        /// <param name="nodes"></param>
        /// <returns></returns>
        private static bool ExistsNode(string code, List<RegionNode> nodes)
        {
            if (nodes == null || nodes.Count == 0) return false;
            RegionNode nd = nodes.FirstOrDefault(t => t.Code.Equals(code, StringComparison.CurrentCultureIgnoreCase));
            if (nd != null)
            {
                _TempRegionNode = nd;
                return true;
            }
            else
            {
                foreach (RegionNode r in nodes)
                {
                    if (ExistsNode(code, r.Nodes)) return true;
                }
                return false;
            }
        }

        /// <summary>
        /// 验证自定义范围是否在指定的范围内
        /// </summary>
        /// <param name="polygon"></param>
        /// <returns></returns>
        public static bool ValidUserRegion(IPolygon polygon)
        {
            if (FrameworkHelper.CurrentUser.IsAdministrator()) return true;//离线
            if (RegionList == null || RegionList.Count == 0) return false;
            if (FrameworkHelper.CurrentUser.UserRegions == null || FrameworkHelper.CurrentUser.UserRegions.Count == 0) return false;
            if (UserRegion == null)
                UserRegion = GetUserRegion();
            if (UserRegion == null) return false;
            IPolygon newgeo = ((IPolygon)UserRegion).Intersect(polygon);
            if (newgeo == null || newgeo.IsEmpty) return false;
            if (newgeo.Length < 0.0002) return false;
            return true;
        }

        /// <summary>
        /// 获取用户范围权限
        /// </summary>
        /// <returns></returns>
        public static IGeometry GetUserRegion()
        {
            if (ManageHelper.PrivilegeCfg == null)
            {
                ManageHelper.PrivilegeCfg = ConfigHelper.GetObject<PrivilegeConfig>();
            }
            if (!RegionList.ContainsKey(ManageHelper.PrivilegeCfg.RegionLayerName)) return null;
            IFeatureClass featcls = RegionList[ManageHelper.PrivilegeCfg.RegionLayerName];
            string w = "";
            foreach (string c in FrameworkHelper.CurrentUser.UserRegions)
            {
                if (string.IsNullOrWhiteSpace(c)) continue;
                w += " or " + ManageHelper.PrivilegeCfg.RegionFieldName + " = '" + c + "'";
            }
            if (string.IsNullOrWhiteSpace(w)) return null;
            IQueryFilter flt = new QueryFilter();
            flt.WhereClause = w.Substring(3);
            IFeatureCursor cur = featcls.Search(flt, false);
            IFeature f = null;
            IGeometry geo = null;
            while ((f = cur.NextFeature()) != null)
            {
                if (f.Shape.IsEmpty) continue;
                if (geo == null) geo = f.ShapeCopy;
                else
                {
                    geo = geo.Union(f.ShapeCopy);
                }
            }
            return geo;
        }
        
    }

    /// <summary>
    /// 行政区对象节点，不记录空间位置，由于行政区节点过多后导致内存溢出
    /// </summary>
    public class RegionNode
    {
        /// <summary>
        /// 编号
        /// </summary>
        public int OID { get; set; }

        /// <summary>
        /// 行政区名称
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 行政区编码
        /// </summary>
        public string Code { get; set; }

        /// <summary>
        /// 所在图层（数据集）名称
        /// </summary>
        public string LayerName { get; set; }
        
        /// <summary>
        /// 下一级行政区
        /// </summary>
        public List<RegionNode> Nodes { get; set; }
    }

    /// <summary>
    /// 区域数据结构
    /// </summary>
    [Serializable]
    public class GeoRegion
    {
        /// <summary>
        /// 名称
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// 编码
        /// </summary>
        public string Code { get; set; }

        /// <summary>
        /// 图形
        /// </summary>
        public IGeometry Geometry { get; set; }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return Name;
        }
    }

}
